package com.boco.config;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import org.springframework.data.rest.core.annotation.RestResource;
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
import org.springframework.data.rest.core.mapping.RepositoryDetectionStrategy;
import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurer;
import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurerAdapter;

import javax.persistence.Entity;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author pandengke/pdkkpdk@163.com
 * @date 2018/9/29
 */
@Configuration
public class RestConfiguration {
    /**
     * 为了解决Spring Data Rest不暴露ID字段的问题。
     */
    @Bean
    public RepositoryRestConfigurer repositoryRestConfigurer() {

        return new RepositoryRestConfigurerAdapter() {

            @Override
            public void configureRepositoryRestConfiguration(
                    RepositoryRestConfiguration config) {
                final ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
                provider.addIncludeFilter(new AnnotationTypeFilter(Entity.class));
                final Set<BeanDefinition> beans = provider.findCandidateComponents("com.boco");
                config.exposeIdsFor(beans.stream().map(beanDefinition -> {
                    try {
                        return Class.forName(beanDefinition.getBeanClassName());
                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                        return null;
                    }
                }).collect(Collectors.toList()).toArray(new Class<?>[beans.size()]));

                config.setRepositoryDetectionStrategy(new RepositoryDetectionStrategy() {
                    private boolean bocoExporte(RepositoryMetadata metadata) {
                       return isExplicitlyExported(metadata.getDomainType(), true);
                    }

                    @Override
                    public boolean isExported(RepositoryMetadata metadata) {
                        return RepositoryDetectionStrategy.RepositoryDetectionStrategies.DEFAULT.isExported(metadata) && bocoExporte(metadata);
                    }
                });
            }
        };
    }

    private static boolean isExplicitlyExported(Class<?> type, boolean fallback) {

        RepositoryRestResource restResource = AnnotationUtils.findAnnotation(type, RepositoryRestResource.class);

        if (restResource != null) {
            return restResource.exported();
        }

        RestResource resource = AnnotationUtils.findAnnotation(type, RestResource.class);

        if (resource != null) {
            return resource.exported();
        }

        return fallback;
    }
}
